Pocket Forth desk accessory version 1.6.3 4 July 1993
The Pocket Forth desk accessory, version 1.6.3, is provided for the convenience of users of system 6 and earlier. All of the features of 1.5 are preserved and some features of the release 6.2 application are added. This document adds to the manual.
New features (from 0.6.2 and 0.6.3) included in this version:
floating point numbers
,S and ?GESTALT
INTERPRET
\
DEPTH
WARM
The word GROW is also included allowing a very small dictionary to be used. The initial size is 32K bytes
The following features of version 0.6 are not included because they are are based on Apple Events and are not used by desk accessories:
AE: and ;AE
WARM
BYE
drag & drop programming
Some of the actions of the desk accessory are different than those of the application. The following sections explain the differences.
Machine Language
The registers D4 and D5 are used to store important information about the system. Preserve their contents if you use them.
Events
The desk accessory has three additional variables in the +MD table:
_name_ _address_
MyID 30 +md
Keydown 32 +md
Cursor 34 +md
• MyID contains the resource ID of the DICT and other owned resources. See the resource section.
• Keydown is a handler that executes when a key is pressed. It contains the text interpreter, so change it carefully if you want to return to Forth. See the turnkey section.
• Cursor executes periodically like Idle. It should be used for changing the cursor shape if necessary. By default, Cursor does nothing.
The desk accessory is missing these variables:
_name_ _reason_
AppleMenu menu handles not needed by DAs
FileMenu ditto
EditMenu ditto
all other variables with an address of 136 +MD or greater.
Menus
The top of the Edit menu and an empty menu available to the DA.
The DA's menu structure is a subset of the application's. The Edit menu pointer is in the same position, but the the empty menu slot of the DA is where the application's File menu pointer would be in the application. See the diagram in the manual that accompanies the discussion of menus.
The DA's additional menu is ID number -1. Create a double variable to hold its handle. The Edit menu is not numbered by the DA because selections from it are handled as discrete messages. There is no Edit menu handle since it is owned by the host application rather than the DA.
Resources
The Pocket Forth DA is composed entirely of resources, as shown in the following list:
type id size description
DICT -15552 5908 dictionary code
DRVR 26 414 driver code
P4th -15552 26 signature
WIND -15552 38 main window
Using system software prior to version 7, desk accessories are installed into the system or suitcase files. During the installation process the ID numbers of resources may change. Because of this, desk accessories own certain resource ID numbers so that installed DAs can find their resources. Each DA is allowed to own up to 16 resources of each type. The numbers owned are derived from a formula: OwnedID = -16384 + (DRVR ID * 32) + index where the index is 0 to 15.
Pocket Forth programs need not calculate owned resources this way. An unnamed variable, called MyID (30 +md), has the ID of the first owned resource. Get additional resource IDs by adding an index of 1 through 15 to the owned ID.
To use resources in a program, create and install them into a copy of Pocket Forth. The first resource of each type should be numbered the same as the DICT resource in the file. Additional resources of the same type are that number plus one, plus two, etc. Use ResEdit or an equivalent program to do the resource surgery. Then, if using an older system, install the DA with the Font/DA Mover. Your resources will be moved along with Pocket Forth's original ones.
This example gets a 'P4th' resource from the desk accessory and displays it:
30 +md @ constant MYID ( the resource ID )
: .P4th ( -- ) \ print the P4th resource data
0 0 2>r \ room for a result
,s P4th 2>r \ the resource type
myid >r \ the resource ID
,$ A9A0 \ _GetResource
2r> 2dup dl@ 2>r ,$ A884 \ _DrawString
2>r ,$ A9A3 ; \ _ReleaseResource
Turnkey
The desk accessory has handlers for button down, key down, update and activate events and open, close, idle, cursor, Edit and other menu messages. Button, activate and update events, idle, cursor and menu messages should be set as described in the events and menu sections of this document or the manual.
Key down handlers are unique to the DA version. The key data is found on the stack when the handler is run. The low byte of the key data is the ASCII value of the key pressed and the high byte is the key code. Typically, the key down handler begins with "255 AND" to mask out the key code, leaving the ASCII code on the stack. Replace the normal key down handler to seal off the interpreter if access to Forth isn't desirable.
It is possible to write a key down handler that passes key data through to the interpreter after you are done with it. This example implements a tab key that emits four spaces, but runs the interpreter normally otherwise. Get the address of the interpreter's key handle, it's in the handler variable at startup:
: W/TABS ( n -- ) ( the interpret routine with tabs )
255 AND \ get ASCII
DUP 9 = IF \ if its a tab key
DROP SPACE SPACE SPACE SPACE \ drop code, emit spaces
ELSE ,$ 4EEB [ ikey , ] THEN ; \ jmp ikey(bp)
' w/tabs 32 +md ! ( install into key handler )
Auto key events are handled by the key down handler. See below for how to mask out unwanted events if you do not want to handle auto key events as key down events.
Open and close handlers work in tandem to create and destroy transient data structures such as handles, menus, windows, etc. The open message happens at the beginning, right after the DA is initialized. Open message handlers should be written with some limitations in mind. Particularly, the driver's control routine has not been entered yet, meaning that events and messages cannot be received nor is the parameter block of the DA accessible. Because of this, the open handler should not try to use events.
Memory structures on the heap, created in the open routine or the body of the program, should eventually be destroyed or they will accumulate in the heap. The usual way to remove heap items is to call the appropriate ROM routine during the close handler. For example, if a handle is created in the open routine, dispose of it in the close routine.
The following example produces a turnkey DA. Don't actually save it because it doesn't do much.
( Handler demo DA )
: MYACT ( flag -- ) IF ." Activated"
ELSE ." Deactivated" THEN cr ;
: MYUP ( -- ) ." Updated" cr ;
: MYBUTT ( -- ) ." Mouse button pressed" cr ;
: MYKEY ( n -- ) 255 and emit space ." Key pressed" cr ;
[ ' myopen literal ] 26 +md ! ( set the open handler )
[ ' myclose literal ] 22 +md ! ( set the close handler )
[ ' mycurs literal ] 34 +md ! ( set the cursor handler )
[ ' myidle literal ] 20 +md ! ( set the idle handler )
[ ' mykey literal ] 32 +md ! ( set the key down handler )
[ ' mybutt literal ] 16 +md ! ( set the button handler )
[ ' myup literal ] 14 +md ! ( set the update handler )
[ ' myact literal ] 12 +md ! ; ( set the activate handler )
start ( save ) ( DON'T save unless you really want this )
As you can see by running this demo, idle and cursor events overwhelm the other events, so that your DA will be called often enough. If idle messages or other events are not required, they can be ignored by modifying the Pocket Forth DRVR with ResEdit.
The rate the idle handler is called is initially set to run 30 times a second. This can be changed with ResEdit. The value in the drvrDelay field represents the time between idle messages in sixtieths of a second. A value of zero lets the idle routine run as often as possible. The drvrFlags field of the DRVR's header is normally $6400. A value of $4400 causes idle messages to be ignored.
The drvrEMask field contains the event mask for the DA (see Inside Macintosh, the Event Manager, for details on constructing an event mask.) Only events that are normally enabled are handled by Pocket Forth, even if the event mask is changed to enable other events. If the event mask is changed to ignore some normally handled events, those events will be ignored.
NOTE: The first four fields of the DRVR's header are the only part of the DRVR that should ever be changed. Modifying the routine addresses will cause an error.
If you can't find everything you need, or have suggestions, bug reports, questions or comments, write to me:
Chris Heilman
[70566,1474] on CompuServe,
cheilman on American Online,
heilman@pc.maricopa.edu via internet email or
PO Box 8345
Phoenix, AZ 85066-8345 via the US postal service.
My attendance on the commercial services is sporadic, however I usually read my email daily (weekdays) from the internet.